home *** CD-ROM | disk | FTP | other *** search
/ AMIGA-CD 2 / Amiga-CD - Volume 2.iso / gepackte_disketten / 1994 / 08_94_5.dms / 08_94_5.adf / term-4.0-Source.lha / termLocale.c < prev    next >
C/C++ Source or Header  |  1994-07-15  |  17KB  |  876 lines

  1. /*
  2. **    termLocale.c
  3. **
  4. **    Localization support routines
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* The catalog data is stored in the following format. */
  13.  
  14. struct CatCompArrayType
  15. {
  16.     LONG    cca_ID;
  17.     STRPTR    cca_Str;
  18. };
  19.  
  20. extern struct CatCompArrayType    *AppStrings;
  21. extern LONG             NumAppStrings;
  22.  
  23.     /* LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn):
  24.      *
  25.      *    Open string translation tables.
  26.      */
  27.  
  28. VOID __regargs
  29. LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn,LONG Version)
  30. {
  31.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  32.     {
  33.         if(LocaleBase -> lb_SysPatches)
  34.         {
  35.             strcpy(ConvNumber,"%lD");
  36.             strcpy(ConvNumber10,"%10lD");
  37.  
  38.             if(Catalog = OpenCatalog(NULL,CatalogName,
  39.                 OC_BuiltInLanguage,    BuiltIn,
  40.                 OC_BuiltInCodeSet,    0,
  41.             TAG_DONE))
  42.             {
  43.                 BOOL TooOld = FALSE;
  44.  
  45.                     // Don't load an outdated catalog file
  46.  
  47.                 if(Catalog -> cat_Version < Version)
  48.                     TooOld = TRUE;
  49.                 else
  50.                 {
  51.                     if(strcmp(GetCatalogStr(Catalog,MSG_OFFSET_TEST1_TXT,""),"v4.0"))
  52.                         TooOld = TRUE;
  53.                 }
  54.  
  55.                 if(TooOld)
  56.                 {
  57.                     if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  58.                     {
  59.                         MyEasyRequest(NULL,"The catalog file is too old to be used\nwith this `term' revision.","Continue");
  60.  
  61.                         CloseLibrary(IntuitionBase);
  62.  
  63.                         IntuitionBase = NULL;
  64.                     }
  65.  
  66.                     CloseCatalog(Catalog);
  67.  
  68.                     Catalog = NULL;
  69.                 }
  70.             }
  71.  
  72.             Locale = OpenLocale(NULL);
  73.         }
  74.         else
  75.         {
  76.             if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  77.             {
  78.                 MyEasyRequest(NULL,"Your \"locale.library\" is not installed correctly.","Continue");
  79.  
  80.                 CloseLibrary(IntuitionBase);
  81.  
  82.                 IntuitionBase = NULL;
  83.             }
  84.  
  85.             strcpy(ConvNumber,"%ld");
  86.             strcpy(ConvNumber10,"%10ld");
  87.  
  88.             CloseLibrary(LocaleBase);
  89.  
  90.             LocaleBase = NULL;
  91.         }
  92.     }
  93.     else
  94.     {
  95.         strcpy(ConvNumber,"%ld");
  96.         strcpy(ConvNumber10,"%10ld");
  97.     }
  98. }
  99.  
  100.     /* LocaleClose():
  101.      *
  102.      *    Close the translation tables.
  103.      */
  104.  
  105. VOID
  106. LocaleClose()
  107. {
  108.     if(Locale)
  109.     {
  110.         CloseLocale(Locale);
  111.  
  112.         Locale = NULL;
  113.     }
  114.  
  115.     if(Catalog)
  116.     {
  117.         CloseCatalog(Catalog);
  118.  
  119.         Catalog = NULL;
  120.     }
  121.  
  122.     if(LocaleBase)
  123.     {
  124.         CloseLibrary(LocaleBase);
  125.  
  126.         LocaleBase = NULL;
  127.     }
  128. }
  129.  
  130.     /* LanguageCheck():
  131.      *
  132.      *    Checks to see if the currently selected language
  133.      *    is english.
  134.      */
  135.  
  136. VOID
  137. LanguageCheck()
  138. {
  139.     if(Locale && Catalog)
  140.     {
  141.         if(Locale -> loc_LanguageName)
  142.         {
  143.             if(!Stricmp(Locale -> loc_LanguageName,"english.language"))
  144.                 English = TRUE;
  145.             else
  146.                 English = FALSE;
  147.         }
  148.         else
  149.             English = FALSE;
  150.     }
  151.     else
  152.         English = TRUE;
  153. }
  154.  
  155.     /* GadToolsStrlen(STRPTR *String):
  156.      *
  157.      *    Custom version of strlen, useful for gadtools object titles
  158.      *    with embedded underscore characters.
  159.      */
  160.  
  161. WORD __regargs
  162. GadToolsStrlen(STRPTR String)
  163. {
  164.     WORD Len = 0;
  165.  
  166.     while(*String)
  167.     {
  168.         if(*String++ != '_')
  169.             Len++;
  170.     }
  171.  
  172.     return(Len);
  173. }
  174.  
  175.     /* GadToolsLongestString(WORD From,WORD To):
  176.      *
  177.      *    Determines the longest string used by a gadtools
  178.      *    control panel.
  179.      */
  180.  
  181. WORD __regargs
  182. GadToolsLongestString(WORD From,WORD To)
  183. {
  184.     STRPTR    Text;
  185.     WORD    MaxLen = 0,
  186.         Len,i;
  187.  
  188.     for(i = From ; i <= To ; i++)
  189.     {
  190.         if(Text = LocaleString(i))
  191.         {
  192.             if((Len = GadToolsStrlen(Text)) > MaxLen)
  193.                 MaxLen = Len;
  194.         }
  195.     }
  196.  
  197.     return(MaxLen);
  198. }
  199.  
  200.     /* LocaleSeconds(WORD Seconds):
  201.      *
  202.      *    Return seconds in proper format.
  203.      */
  204.  
  205. STRPTR __regargs
  206. LocaleSeconds(WORD Seconds)
  207. {
  208.     STATIC UBYTE Time[10];
  209.  
  210.     if(Locale)
  211.         SPrintf(Time,"%2lD%s%02lD",Seconds / 100,Locale -> loc_DecimalPoint,Seconds % 100);
  212.     else
  213.         SPrintf(Time,"%2ld.%02ld",Seconds / 100,Seconds % 100);
  214.  
  215.     return(Time);
  216. }
  217.  
  218.     /* SmallCurrency():
  219.      *
  220.      *    Support function for the rates control panel, returns a formatted
  221.      *    string to contain a string like "cents/unit".
  222.      */
  223.  
  224. STRPTR
  225. SmallCurrency()
  226. {
  227.     STATIC UBYTE Buffer[30];
  228.  
  229.     if(Locale)
  230.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),Locale -> loc_MonSmallCS);
  231.     else
  232.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),"Pay");
  233.  
  234.     return(Buffer);
  235. }
  236.  
  237.     /* InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator):
  238.      *
  239.      *    Tricky stuff, folks! This beauty will insert grouping characters
  240.      *    into a readily-prepared string buffer filled with numeric
  241.      *    contents. It takes the group separator tokens and group separator
  242.      *    strings into account.
  243.      */
  244.  
  245. VOID __regargs
  246. InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator)
  247. {
  248.     UBYTE    LocalBuffer[80];    // Sufficient, but too large
  249.     STRPTR    Index;
  250.     LONG    i,j,SeparatorSize;
  251.     WORD    Count;            // How many characters per group
  252.     BOOL    RepeatGroupCount;    // Keep repeating group size until end
  253.  
  254.         // Set up for the first group
  255.  
  256.     switch(*GroupData)
  257.     {
  258.         case 0:            // Repeat current grouping scheme until end
  259.         case 255:        // No further grouping is to be performed
  260.  
  261.             Count = 0;
  262.  
  263.             break;
  264.  
  265.         default:        // Initial group size
  266.  
  267.             RepeatGroupCount = FALSE;
  268.  
  269.             Count = *GroupData++;
  270.  
  271.             break;
  272.     }
  273.  
  274.         // Check the size of the group separator string
  275.  
  276.     if((SeparatorSize = strlen(GroupSeparator) - 1) < 1)
  277.         Count = 0;
  278.  
  279.         // That where we'll start
  280.  
  281.     Index = LocalBuffer;
  282.  
  283.         // Build the string back to front, we will reverse it later
  284.  
  285.     for(i = strlen(Buffer) - 1, j = 1 ; i >= 0 ; i--, j++)
  286.     {
  287.             // Pick up the next number character
  288.  
  289.         *Index++ = Buffer[i];
  290.  
  291.             // Are we to insert the grouping characters here?
  292.  
  293.         if(Count && j == Count)
  294.         {
  295.             LONG k;
  296.  
  297.                 // Insert the grouping characters
  298.  
  299.             for(k = SeparatorSize ; k >= 0 ; k--)
  300.                 *Index++ = GroupSeparator[k];
  301.  
  302.                 // Reset the group size counter
  303.  
  304.             j = 0;
  305.  
  306.                 // Pick up the next grouping token?
  307.  
  308.             if(!RepeatGroupCount)
  309.             {
  310.                     // Ok, what kind of token is it?
  311.  
  312.                 switch(*GroupData)
  313.                 {
  314.                     case 0:        // Repeat current grouping scheme
  315.  
  316.                         RepeatGroupCount = TRUE;
  317.                         break;
  318.  
  319.                     case 255:    // Perform no further grouping
  320.  
  321.                         Count = 0;
  322.                         break;
  323.  
  324.                     default:    // New group size
  325.  
  326.                         Count = *GroupData++;
  327.                         break;
  328.                 }
  329.             }
  330.         }
  331.     }
  332.  
  333.         // Look how long the resulting string is
  334.  
  335.     j = (LONG)((ULONG)Index - (ULONG)LocalBuffer) - 1;
  336.  
  337.         // Copy it back
  338.  
  339.     Index = Buffer;
  340.  
  341.         // Reverse the order of characters while copying
  342.  
  343.     for(i = j ; i >= 0 ; i--)
  344.         *Index++ = LocalBuffer[i];
  345.  
  346.         // Provide null-termination
  347.  
  348.     *Index = 0;
  349. }
  350.  
  351. VOID __regargs
  352. ConvertMonetaryQuantity(LONG Units,STRPTR Destination,BOOL UseCurrency)
  353. {
  354.     UBYTE    IntegerBuffer[80];    // Sufficient, but too large
  355.  
  356.     STRPTR    SignText,        // Signed/unsigned quantity text
  357.         SpaceText,        // Currency/number separation
  358.         Currency;        // The name of the currency
  359.     UBYTE    SpaceSep,        // A space separates currency and quantity?
  360.         SignPos,        // Where to place the sign text
  361.         CSPos;            // Where to place the currency text
  362.     BYTE    Sign;            // Negative or positive quantity?
  363.  
  364.         // Negative quantity?
  365.  
  366.     if(Units < 0)
  367.     {
  368.         Sign = -1;
  369.  
  370.         Units = -Units;
  371.     }
  372.     else
  373.         Sign = 1;
  374.  
  375.         // Does this currency sport a fractional smaller currency?
  376.  
  377.     if(Locale -> loc_MonFracDigits)
  378.     {
  379.         UBYTE    NumberBuffer[5],
  380.             FractionBuffer[40];
  381.         LONG    Integer,
  382.             Fraction,
  383.             Scale;
  384.         WORD    i;
  385.  
  386.             // Prepare the formatting string
  387.  
  388.         SPrintf(NumberBuffer,"%%0%ldld",Locale -> loc_MonFracDigits);
  389.  
  390.             // Turn the number of fractional digits into a power of ten
  391.  
  392.         for(i = 0, Scale = 1 ; i < Locale -> loc_MonFracDigits ; i++)
  393.             Scale *= 10;
  394.  
  395.             // Split the quantity in integer and fractional part
  396.  
  397.         Integer        = Units / Scale;
  398.         Fraction    = Units % Scale;
  399.  
  400.             // Build the integer text
  401.  
  402.         SPrintf(IntegerBuffer,"%ld",Integer);
  403.  
  404.         InsertGrouping(IntegerBuffer,Locale -> loc_MonGrouping,Locale -> loc_MonGroupSeparator);
  405.  
  406.             // Build the fractional text
  407.  
  408.         SPrintf(FractionBuffer,NumberBuffer,Fraction);
  409.  
  410.         InsertGrouping(FractionBuffer,Locale -> loc_MonFracGrouping,Locale -> loc_MonFracGroupSeparator);
  411.  
  412.             // Add the monetary decimal point
  413.  
  414.         strcat(IntegerBuffer,Locale -> loc_MonDecimalPoint);
  415.  
  416.             // Add the fractional part
  417.  
  418.         strcat(IntegerBuffer,FractionBuffer);
  419.     }
  420.     else
  421.     {
  422.             // Build the integer text
  423.  
  424.         SPrintf(IntegerBuffer,"%ld",Units);
  425.  
  426.         InsertGrouping(IntegerBuffer,Locale -> loc_MonGrouping,Locale -> loc_MonGroupSeparator);
  427.     }
  428.  
  429.         // Pick up the appropriate formatting parameters
  430.  
  431.     if(Sign < 0)
  432.     {
  433.         SignText    = Locale -> loc_MonNegativeSign;
  434.         SpaceSep    = Locale -> loc_MonNegativeSpaceSep;
  435.         SignPos        = Locale -> loc_MonNegativeSignPos;
  436.         CSPos        = Locale -> loc_MonNegativeCSPos;
  437.     }
  438.     else
  439.     {
  440.         SignText    = Locale -> loc_MonPositiveSign;
  441.         SpaceSep    = Locale -> loc_MonPositiveSpaceSep;
  442.         SignPos        = Locale -> loc_MonPositiveSignPos;
  443.         CSPos        = Locale -> loc_MonPositiveCSPos;
  444.     }
  445.  
  446.         // Are we to use the currency symbol?
  447.  
  448.     if(UseCurrency)
  449.     {
  450.             // Pick up the currency text
  451.  
  452.         Currency = Locale -> loc_MonCS;
  453.  
  454.             // Take care of the separation information
  455.  
  456.         if(SpaceSep == SS_NOSPACE)
  457.             SpaceText = "";
  458.         else
  459.             SpaceText = " ";
  460.     }
  461.     else
  462.         Currency = SpaceText = "";
  463.  
  464.         // Now merge all the information into one single string
  465.  
  466.     if(CSPos == CSP_PRECEDES)
  467.     {
  468.         switch(SignPos)
  469.         {
  470.             case SP_PARENS:
  471.  
  472.                 // Currency (Space) Sign Value
  473.                 SPrintf(Destination,"(%s%s%s%s)",Currency,SpaceText,SignText,IntegerBuffer);
  474.                 break;
  475.  
  476.             case SP_PREC_ALL:
  477.  
  478.                 // Sign Currency (Space) Value
  479.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  480.                 break;
  481.  
  482.             case SP_SUCC_ALL:
  483.  
  484.                 // Currency (Space) Value Sign
  485.                 SPrintf(Destination,"%s%s%s%s",Currency,SpaceText,IntegerBuffer,SignText);
  486.                 break;
  487.  
  488.             case SP_PREC_CURR:
  489.  
  490.                 // Sign Currency (Space) Value
  491.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  492.                 break;
  493.  
  494.             case SP_SUCC_CURR:
  495.  
  496.                 // Currency Sign (Space) Value
  497.                 SPrintf(Destination,"%s%s%s%s",Currency,SignText,SpaceText,IntegerBuffer);
  498.                 break;
  499.         }
  500.     }
  501.     else
  502.     {
  503.         switch(SignPos)
  504.         {
  505.             case SP_PARENS:
  506.  
  507.                 // Sign Value (Space) Currency
  508.                 SPrintf(Destination,"(%s%s%s%s)",SignText,IntegerBuffer,SpaceText,Currency);
  509.                 break;
  510.  
  511.             case SP_PREC_ALL:
  512.  
  513.                 // Sign Value (Space) Currency
  514.                 SPrintf(Destination,"%s%s%s%s",SignText,IntegerBuffer,SpaceText,Currency);
  515.                 break;
  516.  
  517.             case SP_SUCC_ALL:
  518.  
  519.                 // Value (Space) Currency Sign
  520.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  521.                 break;
  522.  
  523.             case SP_PREC_CURR:
  524.  
  525.                 // Value (Space) Sign Currency
  526.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,SignText,Currency);
  527.                 break;
  528.  
  529.             case SP_SUCC_CURR:
  530.  
  531.                 // Value (Space) Currency Sign
  532.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  533.                 break;
  534.         }
  535.     }
  536. }
  537.  
  538.     /* CreateSum(LONG Quantity):
  539.      *
  540.      *    Create a string containing a monetary quantity formatted
  541.      *    according to the current locale rules.
  542.      */
  543.  
  544. STRPTR __regargs
  545. CreateSum(LONG Quantity,BYTE UseCurrency)
  546. {
  547.     STATIC UBYTE Buffer[100];
  548.  
  549.     if(Locale)
  550.         ConvertMonetaryQuantity(Quantity,Buffer,UseCurrency);
  551.     else
  552.         SPrintf(Buffer,"%ld.%02ld",Quantity / 100,Quantity % 100);
  553.  
  554.     return(Buffer);
  555. }
  556.  
  557.     /* LocalizeString(STRPTR *Strings,WORD From,WORD To):
  558.      *
  559.      *    Localize an array of strings.
  560.      */
  561.  
  562. VOID __regargs
  563. LocalizeString(STRPTR *Strings,WORD From,WORD To)
  564. {
  565.     WORD i,j;
  566.  
  567.     for(i = From, j = 0 ; i <= To ; i++)
  568.     {
  569.         if(!Strings[j])
  570.             Strings[j++] = LocaleString(i);
  571.     }
  572. }
  573.  
  574.     /* LocalizeMenu(struct NewMenu *Menu,WORD From):
  575.      *
  576.      *    Localize a NewMenu definition.
  577.      */
  578.  
  579. VOID __regargs
  580. LocalizeMenu(struct NewMenu *Menu,WORD From)
  581. {
  582.     STRPTR Label,Shortcut;
  583.  
  584.         while(Menu -> nm_Type != NM_END)
  585.     {
  586.         Shortcut = LocaleString(From);
  587.  
  588.         if(Shortcut[0] && !Shortcut[1])
  589.             Label = Shortcut + 2;
  590.         else
  591.         {
  592.             Label        = Shortcut;
  593.             Shortcut    = NULL;
  594.         }
  595.  
  596.         switch(Menu -> nm_Type)
  597.         {
  598.             case NM_TITLE:
  599.  
  600.                 Menu -> nm_Label = Label;
  601.  
  602.                 From++;
  603.  
  604.                 break;
  605.  
  606.             case NM_ITEM:
  607.             case NM_SUB:
  608.  
  609.                 if(Menu -> nm_Label != NM_BARLABEL)
  610.                 {
  611.                     Menu -> nm_Label    = Label;
  612.                     Menu -> nm_CommKey    = Shortcut;
  613.  
  614.                     From++;
  615.                 }
  616.  
  617.                 break;
  618.         }
  619.  
  620.         Menu++;
  621.     }
  622. }
  623.  
  624.     /* LocaleString(LONG ID):
  625.      *
  626.      *    Obtain a string from the translation pool.
  627.      */
  628.  
  629. STRPTR __regargs
  630. LocaleString(LONG ID)
  631. {
  632.     STRPTR Builtin;
  633.  
  634.     if(ID < NumAppStrings && AppStrings[ID] . cca_ID == ID)
  635.         Builtin = AppStrings[ID] . cca_Str;
  636.     else
  637.     {
  638.         LONG i;
  639.  
  640.         Builtin = "";
  641.  
  642.         for(i = 0 ; i < NumAppStrings ; i++)
  643.         {
  644.             if(AppStrings[i] . cca_ID == ID)
  645.             {
  646.                 Builtin = AppStrings[i] . cca_Str;
  647.  
  648.                 break;
  649.             }
  650.         }
  651.     }
  652.  
  653.     if(Catalog)
  654.     {
  655.         STRPTR String = GetCatalogStr(Catalog,ID,Builtin);
  656.  
  657.         if(String[0])
  658.             return(String);
  659.         else
  660.             return(Builtin);
  661.     }
  662.     else
  663.         return(Builtin);
  664. }
  665.  
  666. STRPTR __saveds __stdargs
  667. LocaleHookFunc(struct Hook *Hook,struct LayoutHandle *Handle,LONG ID)
  668. {
  669.     return(LocaleString(ID));
  670. }
  671.  
  672. STATIC LONG __saveds __asm
  673. FormatDateHookFunc(register __a0 struct Hook *Hook,register __a1 UBYTE Char)
  674. {
  675.     STRPTR String = Hook -> h_Data;
  676.  
  677.     *String++ = Char;
  678.  
  679.     Hook -> h_Data = String;
  680.  
  681.     return(TRUE);
  682. }
  683.  
  684.     /* FormatStamp():
  685.      *
  686.      *    Convert a date stamp into human readable
  687.      *    form by taking the current locale parameters
  688.      *    into account.
  689.      */
  690.  
  691. BOOLEAN __regargs
  692. FormatStamp(struct DateStamp *Stamp,STRPTR DateBuffer,STRPTR TimeBuffer,STRPTR BothBuffer,BOOLEAN SubstituteDay)
  693. {
  694.     struct DateStamp Now;
  695.  
  696.         // If no time stamp given, do with current time
  697.  
  698.     if(!Stamp)
  699.         DateStamp(Stamp = &Now);
  700.  
  701.         // Is the current locale available?
  702.  
  703.     if(Locale)
  704.     {
  705.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  706.  
  707.             // Combine date and time text?
  708.  
  709.         if(BothBuffer && !SubstituteDay)
  710.         {
  711.             LocalHook . h_Data = BothBuffer;
  712.  
  713.             FormatDate(Locale,Locale -> loc_DateTimeFormat,Stamp,&LocalHook);
  714.  
  715.             StripSpaces(BothBuffer);
  716.         }
  717.         else
  718.         {
  719.             UBYTE    LocalDateBuffer[40],
  720.                 LocalTimeBuffer[40];
  721.  
  722.                 // Provide storage space
  723.  
  724.             if(BothBuffer)
  725.             {
  726.                 DateBuffer = LocalDateBuffer;
  727.                 TimeBuffer = LocalTimeBuffer;
  728.             }
  729.  
  730.                 // Do we have a date buffer to fill?
  731.  
  732.             if(DateBuffer)
  733.             {
  734.                     // Are we to substitute the current day with
  735.                     // text such as today, yesterday, etc.?
  736.  
  737.                 if(SubstituteDay)
  738.                 {
  739.                     struct DateStamp Today;
  740.  
  741.                         // Get the current time
  742.  
  743.                     DateStamp(&Today);
  744.  
  745.                         // Does the date refer to yesterday?
  746.  
  747.                     if(Stamp -> ds_Days == Today . ds_Days - 1)
  748.                         strcpy(DateBuffer,GetLocaleStr(Locale,YESTERDAYSTR));
  749.                     else
  750.                     {
  751.                             // Does the date refer to today?
  752.  
  753.                         if(Stamp -> ds_Days == Today . ds_Days)
  754.                             strcpy(DateBuffer,GetLocaleStr(Locale,TODAYSTR));
  755.                         else
  756.                         {
  757.                                 // Does the date refer to tomorrow?
  758.  
  759.                             if(Stamp -> ds_Days == Today . ds_Days + 1)
  760.                                 strcpy(DateBuffer,GetLocaleStr(Locale,TOMORROWSTR));
  761.                             else
  762.                                 SubstituteDay = NULL;
  763.                         }
  764.                     }
  765.                 }
  766.  
  767.                 if(!SubstituteDay)
  768.                 {
  769.                     LocalHook . h_Data = DateBuffer;
  770.  
  771.                     FormatDate(Locale,Locale -> loc_DateFormat,Stamp,&LocalHook);
  772.                 }
  773.  
  774.                 StripSpaces(DateBuffer);
  775.             }
  776.  
  777.             if(TimeBuffer)
  778.             {
  779.                 LocalHook . h_Data = TimeBuffer;
  780.  
  781.                 FormatDate(Locale,Locale -> loc_TimeFormat,Stamp,&LocalHook);
  782.  
  783.                 StripSpaces(TimeBuffer);
  784.             }
  785.  
  786.                 // Combine date and time
  787.  
  788.             if(BothBuffer)
  789.             {
  790.                 strcpy(BothBuffer,DateBuffer);
  791.                 strcat(BothBuffer," ");
  792.                 strcat(BothBuffer,TimeBuffer);
  793.             }
  794.         }
  795.     }
  796.     else
  797.     {
  798.         struct DateTime    DateTime;
  799.         UBYTE        LocalDateBuffer[40],
  800.                 LocalTimeBuffer[40];
  801.  
  802.             // Provide storage space
  803.  
  804.         if(BothBuffer)
  805.         {
  806.             DateBuffer = LocalDateBuffer;
  807.             TimeBuffer = LocalTimeBuffer;
  808.         }
  809.  
  810.             // No locale, so we will use dos.library instead.
  811.  
  812.         CopyMem(Stamp,&DateTime . dat_Stamp,sizeof(struct DateStamp));
  813.  
  814.         DateTime . dat_Format    = FORMAT_DOS;
  815.         DateTime . dat_Flags    = SubstituteDay ? DTF_SUBST : NULL;
  816.         DateTime . dat_StrDay    = NULL;
  817.         DateTime . dat_StrDate    = DateBuffer;
  818.         DateTime . dat_StrTime    = TimeBuffer;
  819.  
  820.         if(!DateToStr(&DateTime))
  821.             return(FALSE);
  822.  
  823.         if(DateBuffer)
  824.             StripSpaces(DateBuffer);
  825.  
  826.         if(TimeBuffer)
  827.             StripSpaces(TimeBuffer);
  828.  
  829.             // Combine date and time
  830.  
  831.         if(BothBuffer)
  832.         {
  833.             strcpy(BothBuffer,DateBuffer);
  834.             strcat(BothBuffer," ");
  835.             strcat(BothBuffer,TimeBuffer);
  836.         }
  837.     }
  838.  
  839.     return(TRUE);
  840. }
  841.  
  842.     /* FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds):
  843.      *
  844.      *    Given hours, minutes and seconds, format this data into
  845.      *    a human-readable string.
  846.      */
  847.  
  848. VOID __regargs
  849. FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds)
  850. {
  851.     if(Locale)
  852.     {
  853.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  854.  
  855.         struct DateStamp Stamp;
  856.  
  857.         Stamp . ds_Days        = 0;
  858.         Stamp . ds_Minute    = Hours * 60 + Minutes;
  859.         Stamp . ds_Tick        = MAX(0,Seconds) * TICKS_PER_SECOND;
  860.  
  861.         LocalHook . h_Data = Buffer;
  862.  
  863.         if(Seconds < 0)
  864.             FormatDate(Locale,Locale -> loc_ShortTimeFormat,&Stamp,&LocalHook);
  865.         else
  866.             FormatDate(Locale,Locale -> loc_TimeFormat,&Stamp,&LocalHook);
  867.     }
  868.     else
  869.     {
  870.         if(Seconds < 0)
  871.             SPrintf(Buffer,"%02ld:%02ld",Hours,Minutes);
  872.         else
  873.             SPrintf(Buffer,"%02ld:%02ld:%02ld",Hours,Minutes,Seconds);
  874.     }
  875. }
  876.